﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace TerrainGenerator
{
    public class FPSCamera
    {
        public Vector3 Position { get { return cameraPosition; } }

        GraphicsDevice graphicsDevice;
        Vector3 cameraPosition;
        float yaw;
        float pitch;

        MouseState originalMouseState;

        const float rotationSpeed = 0.01f;
        const float moveSpeed = 2.0f;


        public FPSCamera(GraphicsDevice graphicsDevice, Vector3 cameraPosition, float yaw, float pitch)
        {
            this.graphicsDevice = graphicsDevice;
            this.cameraPosition = cameraPosition;
            this.yaw = yaw;
            this.pitch = pitch;

            Mouse.SetPosition(graphicsDevice.Viewport.Width / 2, graphicsDevice.Viewport.Height / 2);
            originalMouseState = Mouse.GetState();
        }

        public Vector3 CalculateViewVector()
        {
            Matrix cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw);

            Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
            Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
            Vector3 cameraFinalTarget = Position + cameraRotatedTarget;

            return cameraFinalTarget;
        }

        public Matrix CalculateViewMatrix()
        {
            Matrix cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw);

            Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
            Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
            Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;

            Vector3 cameraRotatedUpVector = Vector3.Transform(Vector3.Up, cameraRotation);

            return Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector);
        }

        public void UpdateCamera(KeyboardState keyboardState, MouseState mouseState)
        {
            if (mouseState != originalMouseState)
            {
                float xDifference = mouseState.X - originalMouseState.X;
                float yDifference = mouseState.Y - originalMouseState.Y;
                yaw -= rotationSpeed * xDifference;
                pitch -= rotationSpeed * yDifference;
                Mouse.SetPosition(graphicsDevice.Viewport.Width / 2, graphicsDevice.Viewport.Height / 2);
            }

            Vector3 moveVector = new Vector3(0, 0, 0);
            if (keyboardState.IsKeyDown(Keys.Up) || keyboardState.IsKeyDown(Keys.W))
                moveVector += new Vector3(0, 0, -1);
            if (keyboardState.IsKeyDown(Keys.Down) || keyboardState.IsKeyDown(Keys.S))
                moveVector += new Vector3(0, 0, 1);
            if (keyboardState.IsKeyDown(Keys.Right) || keyboardState.IsKeyDown(Keys.D))
                moveVector += new Vector3(1, 0, 0);
            if (keyboardState.IsKeyDown(Keys.Left) || keyboardState.IsKeyDown(Keys.A))
                moveVector += new Vector3(-1, 0, 0);
            if (keyboardState.IsKeyDown(Keys.Q))
                moveVector += new Vector3(0, 1, 0);
            if (keyboardState.IsKeyDown(Keys.Z))
                moveVector += new Vector3(0, -1, 0);
            AddToCameraPosition(moveVector);
        }

        void AddToCameraPosition(Vector3 vectorToAdd)
        {
            Matrix cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw);
            Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
            cameraPosition += moveSpeed * rotatedVector;
        }
    }
}
